<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>绘制菱形(包含边框)</title>
  <style>
    #myCanvas {
      display: inherit;
      margin: 50px auto 0;
      border: 1px solid #000;
    }
  </style>
</head>

<body>
  <canvas id="myCanvas" width="800" height="500"></canvas>

  <script>
    var canvas = document.getElementById('myCanvas');
    var ctx = canvas.getContext('2d');
    const canvasWidth = canvas.width;
    const canvasHeight = canvas.height;
    console.log('Canvas宽度：', canvasWidth);
    console.log('Canvas高度：', canvasHeight);

    const devicePixelRatio = window.devicePixelRatio || 1;// 2
    console.log(29, 'devicePixelRatio', devicePixelRatio);

    // 设置canvas的CSS宽度和高度
    canvas.style.width = canvas.width + 'px';
    canvas.style.height = canvas.height + 'px';

    // 设置canvas的物理宽度和高度
    canvas.width = canvas.width * devicePixelRatio;
    canvas.height = canvas.height * devicePixelRatio;

    // 缩放绘图上下文，使其与物理像素一致
    ctx.scale(devicePixelRatio, devicePixelRatio);// 防止线条颜色失真
    // ctx.scale(0.5, 0.5);// 缩放一倍

    ctx.strokeStyle = 'rgba(0, 0, 0, 1)';
    ctx.lineWidth = 1; // 线条宽度

    // // 绘制表格的行
    // for (var i = 0; i < 17; i++) {
    //   ctx.beginPath();
    //   ctx.moveTo(0, (i + 1) * 30); // 行的起始点
    //   ctx.lineTo(canvasWidth, (i + 1) * 30); // 行的结束点
    //   ctx.stroke(); // 绘制行
    // }

    // // 绘制表格的列
    // for (var j = 0; j < 16; j++) {
    //   ctx.beginPath();
    //   ctx.moveTo((j + 1) * 50, 0); // 列的起始点
    //   ctx.lineTo((j + 1) * 50, canvasHeight); // 列的结束点
    //   ctx.stroke(); // 绘制列
    // }

    /* 
    绘制菱形，要求输入某个点位中心点位置，以中心点绘制任意宽度，动态输入边框宽度，颜色，菱形背景色(要求背景色区域是宽度减去边框后的)，并在中心点绘制一个的圆点，并且菱形颜色和小球的颜色支持动态参数输入，在菱形正下方某个距离的地方可以输出文字，也可以不输，文字整体居中，写出该函数,函数参数是对象方式传入
    
    */
    // 绘制菱形
    function drawDiamond({ centerX, centerY, width, borderWidth, borderColor, diamondColor, dotColor, dotSize, text, textOffset }) {
      const canvas = document.getElementById('myCanvas');
      const ctx = canvas.getContext('2d');

      // 计算菱形四个顶点的坐标
      const halfWidth = width / 2;
      // const points = [
      //   { x: centerX, y: centerY - halfWidth },
      //   { x: centerX + halfWidth, y: centerY },
      //   { x: centerX, y: centerY + halfWidth },
      //   { x: centerX - halfWidth, y: centerY }
      // ];

      const points = [
        { x: centerX, y: centerY - halfWidth - borderWidth },
        { x: centerX + halfWidth + borderWidth, y: centerY },
        { x: centerX, y: centerY + halfWidth + borderWidth },
        { x: centerX - halfWidth - borderWidth, y: centerY }
      ];

      // 绘制菱形背景
      ctx.beginPath();
      ctx.moveTo(points[0].x, points[0].y);
      ctx.lineTo(points[1].x, points[1].y);
      ctx.lineTo(points[2].x, points[2].y);
      ctx.lineTo(points[3].x, points[3].y);
      ctx.closePath();
      ctx.fillStyle = diamondColor;
      ctx.fill();

      // 绘制菱形边框
      ctx.beginPath();
      ctx.moveTo(points[0].x, points[0].y);
      ctx.lineTo(points[1].x, points[1].y);
      ctx.lineTo(points[2].x, points[2].y);
      ctx.lineTo(points[3].x, points[3].y);
      ctx.closePath();
      ctx.lineWidth = borderWidth;
      ctx.strokeStyle = borderColor;
      ctx.stroke();

      // 绘制圆点
      ctx.beginPath();
      ctx.arc(centerX, centerY, dotSize, 0, Math.PI * 2);
      ctx.fillStyle = dotColor;
      ctx.fill();

      // 绘制文字
      if (text) {
        ctx.font = '12px Arial';
        ctx.textAlign = 'center';
        ctx.fillStyle = 'black';
        ctx.fillText(text, centerX, centerY + halfWidth + textOffset + borderWidth);
      }
    }

    var nodes = [
      { x: 100, y: 100, width: 30 },
      // { x: 200, y: 150, width: 30 },
      { x: 200, y: 200, width: 30 },
      // { x: 200, y: 250, width: 30 },
      { x: 200, y: 300, width: 30 },
      // { x: 200, y: 350, width: 30 },
      { x: 200, y: 400, width: 30 }
    ];

    for (var i = 0; i < nodes.length; i++) {
      var node = nodes[i];
      drawDiamond({
        centerX: node.x,
        centerY: node.y,
        width: node.width,
        borderWidth: 1,
        borderColor: 'black',
        diamondColor: 'rgba(0,0,0,0)',
        dotColor: 'blue',
        dotSize: 2,
      });
    }

    // ctx.quadraticCurveTo((startX + endX) / 2, startY - 50, endX, endY);// 先向上
    // ctx.quadraticCurveTo(startX, (startY + endY) / 2, endX, endY);// 先向下
    // ctx.quadraticCurveTo(startX, startY + (endY - startY) * 1.1, endX, endY);// 更曲线一点

    /* 
    canvas 写一个绘制曲线函数，要求参数为对象，可动态传入开始节点和结束节点的位置，曲线为向下弧度曲线，可支持定义颜色，并且曲线结束时要有一个人字形箭头(类似于计算符号大于号:>)，且方向自然一点

    */
    function drawCurveArrow({ startX, startY, endX, endY, curveColor, arrowColor }) {
      const canvas = document.getElementById('myCanvas');
      const ctx = canvas.getContext('2d');

      // 计算斜率
      const dx = endX - startX;
      const dy = endY - startY;
      const angle = Math.atan2(dy, dx);

      // 一个二次贝塞尔曲线，用于绘制曲线
      ctx.beginPath();
      ctx.moveTo(startX, startY);
      ctx.quadraticCurveTo(startX, startY + (endY - startY) * 1.05, endX, endY);// 1.05就是控制向上向下曲线的曲的程度
      ctx.strokeStyle = curveColor;
      ctx.lineWidth = 2;
      ctx.stroke();

      // 绘制曲线，将结束点的坐标转换为相对于中心点的坐标，然后根据方向角旋转画布。这样就可以在绘制曲线时，以中心点为原点，结束点为坐标系的原点。
      ctx.save();
      ctx.translate(endX, endY);
      ctx.rotate(angle);

      // 绘制箭头
      ctx.restore();
      ctx.beginPath();
      ctx.moveTo(endX, endY);
      ctx.lineTo(endX - 8, endY - 8);
      ctx.lineTo(endX - 5, endY);
      ctx.lineTo(endX - 8, endY + 8);
      ctx.closePath();
      ctx.fillStyle = arrowColor;
      ctx.fill();
      ctx.restore();

    }

    for (let i = 1; i < nodes.length; i++) {
      drawCurveArrow({
        startX: nodes[0].x,
        startY: nodes[0].y,
        endX: nodes[i].x - nodes[i].width / 2,
        endY: nodes[i].y,
        curveColor: 'darkred',
        curveWidth: 3,
        arrowColor: 'darkred'
      });
    }

    canvas.addEventListener('mousemove', debounce(handleMousemove, 300));

    function handleMousemove(event) {
      var rect = canvas.getBoundingClientRect();
      var x = event.clientX - rect.left;
      var y = event.clientY - rect.top;

      for (var i = 0; i < nodes.length; i++) {
        var node = nodes[i];

        if (isWithinDiamond(x, y, node.x, node.y, node.width, node.width)) {
          console.log('i', i);
        }
      }
    }

    /*
      centerX:菱形的中心点x坐标
      centerY:菱形的中心点y坐标
      diamondWidth:菱形的宽度
      diamondHeight: 菱形的高度
    */
    function isWithinDiamond(x, y, centerX, centerY, diamondWidth, diamondHeight) {
      var halfWidth = diamondWidth / 2;
      var halfHeight = diamondHeight / 2;

      // 计算菱形的四个顶点坐标
      var top = centerY - halfHeight;
      var bottom = centerY + halfHeight;
      var left = centerX - halfWidth;
      var right = centerX + halfWidth;

      var dx = Math.abs(x - centerX);
      var dy = Math.abs(y - centerY);

      // 检查点是否在菱形的上边界、下边界、左边界和右边界内
      var isInside = (dx / halfWidth + dy / halfHeight <= 1) &&
        (y >= top) && (y <= bottom) &&
        (x >= left) && (x <= right);

      return isInside;
    }

    function debounce(func, delay) {
      let timeoutId;

      return function () {
        clearTimeout(timeoutId);

        timeoutId = setTimeout(() => {
          func.apply(this, arguments);
        }, delay);
      };
    }
  </script>
</body>

</html>